# app/services/tasks.py

import logging
import os
import re
import asyncio
import tempfile,aiohttp
import json
from datetime import datetime
import subprocess
from app.core.config import settings
from app.db.session import get_db_session
from app.models.models import Job
from app.services.oss_service import upload_file_to_oss, download_file, generate_signed_url, upload_image_to_oss

class TaskManager:

    async def get_video_duration(self, filename):
        try:
            # 使用 ffprobe 获取视频信息
            process = await asyncio.create_subprocess_exec(
                'ffprobe', '-v', 'error',
                '-show_entries', 'format=duration',
                '-of', 'json', filename,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )
            stdout, stderr = await process.communicate()
            if process.returncode == 0:
                output = stdout.decode()
                data = json.loads(output)
                duration = float(data['format']['duration'])
                return duration
            else:
                logging.error(f"ffprobe error: {stderr.decode()}")
                return 0.0
        except Exception as e:
            logging.error(f"获取视频时长时出错：{e}")
            return 0.0

    # 监控任务状态
    async def monitor_job_status(self, job_id: int):
        """
        异步监控任务状态，直到任务完成并处理视频或音频。
        """
        logging.info(f"开始监控 job_id={job_id} 的状态")
        external_api_url = settings.EXTERNAL_API_URL.replace('/task/create', '/task/inspect')
        headers = {
            'Content-Type': settings.CONTENT_TYPE,
            'Authorization': settings.AUTHORIZATION
        }
        payload = {'job_id': job_id}

        max_retries = 360  # 最大轮询次数
        interval = 10     # 每次轮询的间隔（秒）

        for attempt in range(max_retries):
            await asyncio.sleep(interval)

            try:
                async with aiohttp.ClientSession() as session:
                    async with session.post(external_api_url, json=payload, headers=headers, timeout=30) as response:
                        response_data = await response.json()
                        logging.info(f"job_id={job_id} 轮询第 {attempt+1} 次，外部 API 响应：{response_data}")
            except Exception as e:
                logging.error(f"请求外部 API 时出错：{e}")
                continue

            if response_data.get('status') == 3:
                # 任务已完成，处理视频或音频
                # 从数据库中获取任务信息，获取 only_generate_audio 的值
                db = get_db_session()
                job = db.query(Job).filter(Job.job_id == job_id).first()
                if not job:
                    logging.error(f"未找到 job_id={job_id} 的记录")
                    db.close()
                    break

                only_generate_audio = job.only_generate_audio

                if only_generate_audio:
                    # 仅生成音频
                    # 由于外部 API 可能返回的是 video_Url 指向的音频文件
                    audio_url = response_data.get('audio_Url') or response_data.get('video_Url')  # 优先使用 audio_Url，如果没有则使用 video_Url
                    if not audio_url:
                        logging.error("外部 API 响应中缺少 audio_Url 或 video_Url")
                        db.close()
                        break
                    try:
                        # 使用系统临时目录保存音频文件
                        temp_dir = tempfile.gettempdir()
                        local_audio_filename = os.path.join(temp_dir, f"audio_{job_id}.wav")

                        # 下载音频到本地（在线程池中执行阻塞的下载操作）
                        await asyncio.to_thread(download_file, audio_url, local_audio_filename)
                        logging.info(f"已下载音频到本地：{local_audio_filename}")

                        # 上传音频到 OSS（在线程池中执行阻塞的上传操作）
                        oss_audio_url, oss_key = await upload_file_to_oss(local_audio_filename, file_extension='wav')
                        logging.info(f"已上传音频到 OSS：{oss_audio_url}")

                        # 更新数据库中的 audio_url 和 video_time
                        oss_audio_url = re.search(r'xiaorui/[^/]+\.wav', oss_audio_url).group(0)
                        job.audio_url = oss_audio_url

                        # 更新数据库中的 audio_url
                        oss_audio_url = re.search(r'xiaorui/[^/]+\.wav', oss_audio_url).group(0)
                                            # 设置 video_time 为当前时间戳
                        job.video_time = int(datetime.utcnow().timestamp())
                        job.audio_url = oss_audio_url
                        db.commit()
                        logging.info(f"已更新数据库，job_id={job_id} 的 audio_url 和 video_time")

                        # 删除本地音频文件
                        os.remove(local_audio_filename)

                        db.close()
                        break  # 任务已完成，结束轮询
                    except Exception as e:
                        logging.error(f"处理音频时出错：{e}")
                        db.close()
                        break
                else:
                    # 处理视频
                    video_url = response_data.get('video_Url')
                    if not video_url:
                        logging.error("外部 API 响应中缺少 video_Url")
                        db.close()
                        break

                    # 使用系统临时目录保存视频文件
                    temp_dir = tempfile.gettempdir()
                    local_video_filename = os.path.join(temp_dir, f"video_{job_id}.mp4")

                    try:
                        # 下载视频到本地
                        await download_file(video_url, local_video_filename)
                        logging.info(f"已下载视频到本地：{local_video_filename}")

                        # 获取视频时长
                        video_duration = await self.get_video_duration(local_video_filename)
                        logging.info(f"视频时长：{video_duration} 秒")

                        # 上传视频到 OSS
                        oss_video_url, oss_key = await upload_file_to_oss(local_video_filename, file_extension='mp4')
                        logging.info(f"已上传视频到 OSS：{oss_video_url}")


                        # 更新数据库中的 video_url 和 image_url
                        oss_video_url = re.search(r'xiaorui/[^/]+\.mp4', oss_video_url).group(0)
                        # oss_image_url = re.search(r'xiaorui/[^/]+\.jpg', oss_image_url).group(0)
                        job.video_url = oss_video_url
                        # job.image_url = oss_image_url

                        # 设置 video_time 为当前时间戳
                        job.video_time = int(datetime.utcnow().timestamp())
                        # 设置 video_duration
                        job.video_duration = video_duration

                        db.commit()
                        logging.info(f"已更新数据库，job_id={job_id} 的 video_url、image_url、video_time 和 video_duration")


                        # 删除本地视频和图片文件
                        os.remove(local_video_filename)
                        # os.remove(local_image_filename)

                        db.close()
                        break  # 任务已完成，结束轮询
                    except Exception as e:
                        logging.error(f"处理视频时出错：{e}")
                        db.close()
                        break
            elif response_data.get('status') == 4:
                # 任务失败
                logging.error(f"任务 job_id={job_id} 处理失败")
                break
            else:
                # 任务未完成，继续轮询
                continue
        else:
            # 超过最大轮询次数
            logging.error(f"任务 job_id={job_id} 在指定的时间内未完成")
